﻿using GeneticAlgorithms.Operators.Selection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using GeneticAlgorithms.Genomes;
using GeneticAlgorithms.Populations;
using System.Collections.Generic;
using System.Linq;
using System;
using Moq;
using GeneticAlgorithms.Tools;

namespace GeneticAlgorithms.Tests
{
    
    
    /// <summary>
    ///This is a test class for TounamentSelectorTest and is intended
    ///to contain all TounamentSelectorTest Unit Tests
    ///</summary>
    [TestClass()]
    public class TounamentSelectorTest
    {


        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        // 
        //You can use the following additional attributes as you write your tests:
        //
        //Use ClassInitialize to run code before running the first test in the class
        //[ClassInitialize()]
        //public static void MyClassInitialize(TestContext testContext)
        //{
        //}
        //
        //Use ClassCleanup to run code after all tests in a class have run
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //
        //Use TestInitialize to run code before running each test
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //}
        //
        //Use TestCleanup to run code after each test has run
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //}
        //
        #endregion

        [TestMethod()]
        public void SelectGenomesTest()
        {
            TounamentSelector<BinaryGenome, bool> target = new TounamentSelector<BinaryGenome, bool>();
            int length = 20;
            int genomeLength = 10;
            BinaryGenome[] genomes = new BinaryGenome[length];
            Random rnd = new Random();
            genomes.SetValues((i) => new BinaryGenome(genomeLength));
            genomes.ForEach(g => g.Fitness = rnd.NextDouble() * 100);
            List<BinaryGenome> selected = new List<BinaryGenome>();
            for (int i = 0; i < length; i += 2)
            {
                selected.Add(genomes[i].Fitness > genomes[i + 1].Fitness ?
                    genomes[i] : genomes[i + 1]);
            }

            Mock<IGeneticRandomGenerator> randomMock = new Mock<IGeneticRandomGenerator>();
            int j = 0;
            randomMock.Expect(r => r.Next(length)).Returns(() => j++);
            IGeneticRandomGenerator previous = GeneticRandomGenerator.Default;
            GeneticRandomGenerator.Default = randomMock.Object;
            TestSelect(target, genomes, selected);
            GeneticRandomGenerator.Default = previous;
        }

        private void TestSelect(IGeneticSelector<BinaryGenome, bool> target,
            IList<BinaryGenome> genomes, 
            IList<BinaryGenome> expected)
        {
            BinaryPopulation pop = new BinaryPopulation(genomes.Count, genomes[0].Length, null);
            for (int i = 0; i < pop.Count; ++i)
            {
                pop[i] = genomes[i];
            }

            var actual = target.SelectGenomes(pop, expected.Count);//.ToList();
            Assert.IsTrue(expected.SequenceEqual(actual));
        }
    }
}
